#include "tbr_rasterizer.hpp"
#ifndef __SYNTHESIS__
#include <iostream>
#include <iomanip>  // For std::hex, std::dec, std::fixed, std::setprecision
#include <algorithm> // For std::min
#endif

// 辅助函数：从流中读取光栅化器配置参数
void read_rasterizer_config(
    hls::stream<ap_uint<16>>& s_num_triangles_to_rasterizer_in,
    hls::stream<ap_uint<11>>& s_max_x_res_to_rasterizer_in,
    hls::stream<ap_uint<11>>& s_max_y_res_to_rasterizer_in,
    RasterizerConfig& config
) {
    #pragma HLS INLINE OFF // 作为一个 DATAFLOW 阶段之前的配置函数
    config.num_triangles = s_num_triangles_to_rasterizer_in.read(); 
    config.max_x_res = s_max_x_res_to_rasterizer_in.read();
    config.max_y_res = s_max_y_res_to_rasterizer_in.read();
    config.num_tiles_x = (config.max_x_res + TILE_WIDTH - 1) / TILE_WIDTH;
    config.num_tiles_y = (config.max_y_res + TILE_HEIGHT - 1) / TILE_HEIGHT;
}


// -----------------------------------------------------------
// 辅助函数：将 Tile List 从 stream 写入本地 BRAM
// -----------------------------------------------------------
void write_tile_list_to_bram(
    hls::stream<TileListDataPacket>& s_tile_list_in,
    ap_uint<8> num_tiles_x,
    ap_uint<8> num_tiles_y,
    ap_uint<TILE_LIST_MAX_TRIANGLES_PER_TILE_LOG2> local_tile_list_count[MAX_NUM_TILES_Y][MAX_NUM_TILES_X],
    ap_uint<TRIANGLE_ID_BITS> local_tile_list_data[MAX_NUM_TILES_Y][MAX_NUM_TILES_X][TILE_LIST_MAX_TRIANGLES_PER_TILE]
) {
    #pragma HLS INLINE OFF // 作为一个 DATAFLOW 阶段的子函数，不内联

    READ_ALL_TILE_LIST_FROM_STREAM:
    for (ap_uint<8> ty_stream = 0; ty_stream < num_tiles_y; ++ty_stream) {
        #pragma HLS LOOP_TRIPCOUNT min=1 max=MAX_NUM_TILES_Y // TRIPCOUNT 修正
        for (ap_uint<8> tx_stream = 0; tx_stream < num_tiles_x; ++tx_stream) {
            #pragma HLS LOOP_TRIPCOUNT min=1 max=MAX_NUM_TILES_X // TRIPCOUNT 修正
            #pragma HLS PIPELINE II=1

            TileListDataPacket packet = s_tile_list_in.read();
            local_tile_list_count[packet.tile_y][packet.tile_x] = packet.count;
            for (int k = 0; k < TILE_LIST_MAX_TRIANGLES_PER_TILE; ++k) {
                #pragma HLS UNROLL 
                local_tile_list_data[packet.tile_y][packet.tile_x][k] = packet.data[k];
            }

            #ifndef __SYNTHESIS__
            // 新增调试：打印从流中读取并写入本地 BRAM 的 Tile List 数据
            if (packet.tile_y == 0 && packet.tile_x == 0) { // 仅关注 Tile (0,0)
                std::cout << "[TBR_RASTER_DEBUG_STREAM_IN] Received TileListDataPacket for Tile (" << (int)packet.tile_y << "," << (int)packet.tile_x << "):" << std::endl;
                std::cout << "  Count: " << (int)packet.count << std::endl;
                std::cout << "  Triangle IDs (first 5 or up to count): ";
                for (int k = 0; k < std::min((int)packet.count, 5); ++k) {
                    std::cout << (int)packet.data[k] << " ";
                }
                std::cout << std::endl;
            }
            #endif
        }
    }
}

// -----------------------------------------------------------
// 辅助函数：处理单个 Tile 的光栅化
// -----------------------------------------------------------
void rasterize_single_tile(
    ap_uint<8> tile_y_idx,
    ap_uint<8> tile_x_idx,
    const RasterizerConfig& config, // 使用 RasterizerConfig 结构体
    binned_triangle_packet_fixed all_triangles_bram[MAX_NUM_TRIANGLES],
    ap_uint<TILE_LIST_MAX_TRIANGLES_PER_TILE_LOG2> local_tile_list_count[MAX_NUM_TILES_Y][MAX_NUM_TILES_X],
    ap_uint<TRIANGLE_ID_BITS> local_tile_list_data[MAX_NUM_TILES_Y][MAX_NUM_TILES_X][TILE_LIST_MAX_TRIANGLES_PER_TILE],
    zbuffer_ddr_word_t* output_zbuffer_ddr_write,
    color_ddr_word_t* output_framebuffer_ddr,
    hls::stream<PixelWriteCount>& s_tile_pixel_write_counts // 输出到 stream
) {
    #pragma HLS INLINE OFF // 作为一个 DATAFLOW 阶段的子函数，不内联

    // 局部变量用于累加当前 Tile 的写入数
    PixelWriteCount tile_actual_writes_to_ddr = 0; 

    // Determine current tile's pixel coordinate range (global screen coordinates)
    fpal::fp_screen_pixel_idx_t tile_global_min_x_px = tile_x_idx * TILE_WIDTH;
    fpal::fp_screen_pixel_idx_t tile_global_min_y_px = tile_y_idx * TILE_HEIGHT;
    fpal::fp_screen_pixel_idx_t tile_global_max_x_px = tile_global_min_x_px + TILE_WIDTH - 1;
    fpal::fp_screen_pixel_idx_t tile_global_max_y_px = tile_global_min_y_px + TILE_HEIGHT - 1;

    // Clamp tile max coordinates to actual screen resolution
    if (tile_global_max_x_px >= config.max_x_res) tile_global_max_x_px = config.max_x_res - 1;
    if (tile_global_max_y_px >= config.max_y_res) tile_global_max_y_px = config.max_y_res - 1;

    // Read triangle list for current tile (从 local BRAM 读取)
    ap_uint<TILE_LIST_MAX_TRIANGLES_PER_TILE_LOG2> current_tile_triangle_count = local_tile_list_count[tile_y_idx][tile_x_idx];
    ap_uint<TRIANGLE_ID_BITS> current_tile_triangle_ids[TILE_LIST_MAX_TRIANGLES_PER_TILE];
    
    READ_TILE_LIST_LOOP:
    for (ap_uint<TILE_LIST_MAX_TRIANGLES_PER_TILE_LOG2> i = 0; i < current_tile_triangle_count; ++i) {
        #pragma HLS LOOP_TRIPCOUNT min=0 max=TILE_LIST_MAX_TRIANGLES_PER_TILE
        current_tile_triangle_ids[i] = local_tile_list_data[tile_y_idx][tile_x_idx][i]; // <-- 关键读取点

        #ifndef __SYNTHESIS__
        // 新增调试：打印从 local_tile_list_data 读取到的三角形 ID
        if (tile_y_idx == 0 && tile_x_idx == 0 && i < 5) { // 仅关注 Tile (0,0) 的前几个 ID
            std::cout << "[TBR_RASTER_DEBUG_READ_LOCAL_LIST] Tile (" << (int)tile_y_idx << "," << (int)tile_x_idx << ") slot " << (int)i 
                      << " reads Triangle ID: " << (int)current_tile_triangle_ids[i] << std::endl;
        }
        #endif
    }

    // 为当前 Tile 涉及的所有三角形创建本地缓存
    binned_triangle_packet_fixed current_tile_triangles_cache[TILE_LIST_MAX_TRIANGLES_PER_TILE];
    #pragma HLS ARRAY_PARTITION variable=current_tile_triangles_cache complete dim=1 // 完全分区

    // 将需要的三角形数据从共享 BRAM 拷贝到本地缓存
    // 这个循环的 II 取决于 all_triangles_bram 的端口数。ram_t2p 有 2 个读端口，所以 II=1 应该可以。
    // 但为了确保，可以设置为 II=1 并且 LOOP_TRIPCOUNT 明确。
    COPY_TRIANGLES_TO_CACHE:
    for (ap_uint<TILE_LIST_MAX_TRIANGLES_PER_TILE_LOG2> i = 0; i < current_tile_triangle_count; ++i) {
        #pragma HLS LOOP_TRIPCOUNT min=0 max=TILE_LIST_MAX_TRIANGLES_PER_TILE // min=0, max=16
        ap_uint<TRIANGLE_ID_BITS> tri_id = current_tile_triangle_ids[i];
        
        // ======================== 新增调试代码 (TBR_Rasterizer 读取 BRAM 后颜色检查) ========================
        // 引入临时变量，先从 BRAM 读取到此
        binned_triangle_packet_fixed temp_triangle_from_bram = all_triangles_bram[tri_id];

        // --- 修改开始 ---
        // 解包颜色
        ap_uint<24> read_packed_color = temp_triangle_from_bram.packed_pure_color;
        temp_triangle_from_bram.pure_color_R = (read_packed_color >> 16) & 0xFF;
        temp_triangle_from_bram.pure_color_G = (read_packed_color >> 8)  & 0xFF;
        temp_triangle_from_bram.pure_color_B = (read_packed_color >> 0)  & 0xFF;
        // --- 修改结束 ---

#ifndef __SYNTHESIS__
        if (tile_y_idx == 0 && tile_x_idx == 0 && i < 5) { // For the first few triangles in the first tile
            std::cout << "[TBR_RASTER_DEBUG] (Internal) Triangle " << (int)tri_id
                      << " AFTER reading from all_triangles_bram and UNPACKING: R=" << (int)temp_triangle_from_bram.pure_color_R
                      << ", G=" << (int)temp_triangle_from_bram.pure_color_G
                      << ", B=" << (int)temp_triangle_from_bram.pure_color_B << std::endl;
        }
#endif
        // ====================================================================================================
        
        // 然后将临时变量赋值给本地缓存
        current_tile_triangles_cache[i] = temp_triangle_from_bram; 

        // 现有的调试代码，它检查的是从 local cache 读取的值
#ifndef __SYNTHESIS__
        if (tile_y_idx == 0 && tile_x_idx == 0 && i < 5) { // For the first few triangles in the first tile
            std::cout << "[HLS_RASTER_DEBUG] (Internal) Triangle " << (int)tri_id
                      << " AFTER copying to current_tile_triangles_cache: R=" << (int)current_tile_triangles_cache[i].pure_color_R
                      << ", G=" << (int)current_tile_triangles_cache[i].pure_color_G
                      << ", B=" << (int)current_tile_triangles_cache[i].pure_color_B << std::endl;
        }
#endif
        // ====================================================================================================
    }

    RASTER_TILE_Y_LOOP:
    for (fpal::fp_screen_pixel_idx_t y = tile_global_min_y_px; y <= tile_global_max_y_px; ++y) {
        #pragma HLS LOOP_TRIPCOUNT min=1 max=TILE_HEIGHT

        // --- Declare and initialize line buffers for the current scanline ---
        fpal::fp_z_buffer_t line_z_buffer[TILE_WIDTH];
        #pragma HLS ARRAY_PARTITION variable=line_z_buffer complete dim=1 

        fpal::fp_color_channel_t line_color_R[TILE_WIDTH];
        #pragma HLS ARRAY_PARTITION variable=line_color_R complete dim=1

        fpal::fp_color_channel_t line_color_G[TILE_WIDTH];
        #pragma HLS ARRAY_PARTITION variable=line_color_G complete dim=1

        fpal::fp_color_channel_t line_color_B[TILE_WIDTH];
        #pragma HLS ARRAY_PARTITION variable=line_color_B complete dim=1

        CLEAR_LINE_BUFFERS_LOOP:
        for (int i = 0; i < TILE_WIDTH; ++i) {
            line_z_buffer[i] = (fpal::fp_z_buffer_t)65535; // Farthest Z
            line_color_R[i] = (fpal::fp_color_channel_t)0; // Black
            line_color_G[i] = (fpal::fp_color_channel_t)0;
            line_color_B[i] = (fpal::fp_color_channel_t)0;
        }

        fpal::fp_coord_t pixel_y_coord = fpal::to_fp_coord(y) + fpal::to_fp_coord(0.5f);

        TRIANGLE_RASTERIZATION_LOOP_PER_LINE:
        for (ap_uint<TILE_LIST_MAX_TRIANGLES_PER_TILE_LOG2> i = 0; i < current_tile_triangle_count; ++i) {
            #pragma HLS LOOP_TRIPCOUNT min=0 max=TILE_LIST_MAX_TRIANGLES_PER_TILE

            binned_triangle_packet_fixed current_triangle = current_tile_triangles_cache[i]; 

            bool intersects_y = (y >= current_triangle.min_y_px && y <= current_triangle.max_y_px);

            if (!current_triangle.is_valid_triangle || !intersects_y) {
                continue; 
            }
            
            fpal::fp_screen_pixel_idx_t raster_min_x = (current_triangle.min_x_px > tile_global_min_x_px) ? current_triangle.min_x_px : tile_global_min_x_px;
            fpal::fp_screen_pixel_idx_t raster_max_x = (current_triangle.max_x_px < tile_global_max_x_px) ? current_triangle.max_x_px : tile_global_max_x_px;

            fpal::fp_coord_t delta_y_from_v0 = fpal::sub_fx(pixel_y_coord, current_triangle.v0_y_ref);
            fpal::fp_coord_t initial_z_on_line = fpal::add_fx(fpal::to_fp_coord(current_triangle.v0_z_ref), fpal::mul_fx(current_triangle.dzdy, delta_y_from_v0));

            // --- 边缘方程预计算 (per-scanline) ---
            fpal::fp_coord_t edge0_By_plus_C = fpal::add_fx(fpal::mul_fx(current_triangle.edge0_B, pixel_y_coord), current_triangle.edge0_C);
            fpal::fp_coord_t edge1_By_plus_C = fpal::add_fx(fpal::mul_fx(current_triangle.edge1_B, pixel_y_coord), current_triangle.edge1_C);
            fpal::fp_coord_t edge2_By_plus_C = fpal::add_fx(fpal::mul_fx(current_triangle.edge2_B, pixel_y_coord), current_triangle.edge2_C);

            // --- RASTER_TILE_X_LOOP 迭代变量初始化 ---
            fpal::fp_coord_t current_w0, current_w1, current_w2;
            fpal::fp_coord_t pixel_x_coord_initial = fpal::to_fp_coord(raster_min_x) + fpal::to_fp_coord(0.5f);

            // 计算 x = raster_min_x 时的初始 w 值
            current_w0 = fpal::add_fx(fpal::mul_fx(current_triangle.edge0_A, pixel_x_coord_initial), edge0_By_plus_C);
            current_w1 = fpal::add_fx(fpal::mul_fx(current_triangle.edge1_A, pixel_x_coord_initial), edge1_By_plus_C);
            current_w2 = fpal::add_fx(fpal::mul_fx(current_triangle.edge2_A, pixel_x_coord_initial), edge2_By_plus_C);

            // 存储 x 递增 1 时的 A 值
            fpal::fp_coord_t dx_fixed_point_one = fpal::to_fp_coord(1.0f); // 用于计算 pixel_x_coord_current 的增量
            
            RASTER_TILE_X_LOOP:
            for (fpal::fp_screen_pixel_idx_t x = raster_min_x; x <= raster_max_x; ++x) {
                #pragma HLS LOOP_TRIPCOUNT min=1 max=TILE_WIDTH

                // --- is_inside_triangle_tbr 逻辑 ---
                // 在每次迭代中，w0, w1, w2 已经通过加法更新，无需重新计算 Ax+By+C
                bool all_non_negative = (current_w0 >= 0 && current_w1 >= 0 && current_w2 >= 0);
                bool all_non_positive = (current_w0 <= 0 && current_w1 <= 0 && current_w2 <= 0);

                if (all_non_negative || all_non_positive) {
                    // 获取当前像素中心 x 坐标，用于深度插值
                    // 注意：这里的 pixel_x_coord 需要是精确的 x+0.5，不能直接用 x_loop_var
                    // 因为 z 插值需要准确的坐标，而 w 值的增量更新是基于 A*x 的增量
                    fpal::fp_coord_t pixel_x_coord_current = fpal::to_fp_coord(x) + fpal::to_fp_coord(0.5f);
                    
                    fpal::fp_coord_t delta_x_from_v0 = fpal::sub_fx(pixel_x_coord_current, current_triangle.v0_x_ref);
                    
                    fpal::fp_coord_t dz_offset_x = fpal::mul_fx(current_triangle.dzdx, delta_x_from_v0);
                    
                    fpal::fp_coord_t interpolated_z_fx_coord = fpal::add_fx(initial_z_on_line, dz_offset_x);
                    fpal::fp_z_buffer_t interpolated_z = fpal::to_fp_z_buffer(interpolated_z_fx_coord);

                    int local_line_x_idx = (int)(x - tile_global_min_x_px);

                    if (interpolated_z < line_z_buffer[local_line_x_idx]) {
                        line_z_buffer[local_line_x_idx] = interpolated_z;
                        line_color_R[local_line_x_idx] = current_triangle.pure_color_R;
                        line_color_G[local_line_x_idx] = current_triangle.pure_color_G;
                        line_color_B[local_line_x_idx] = current_triangle.pure_color_B;
                    }
                }

                // --- 增量更新 w 值，为下一个 x 准备 ---
                if (x < raster_max_x) { // 避免在循环最后一次迭代后进行不必要的更新
                    current_w0 = fpal::add_fx(current_w0, current_triangle.edge0_A);
                    current_w1 = fpal::add_fx(current_w1, current_triangle.edge1_A);
                    current_w2 = fpal::add_fx(current_w2, current_triangle.edge2_A);
                }
            } // end RASTER_TILE_X_LOOP
        } // end TRIANGLE_RASTERIZATION_LOOP_PER_LINE

        zbuffer_ddr_word_t z_ddr_line_cache[TILE_WIDTH / Z_PER_WORD]; 
        #pragma HLS ARRAY_PARTITION variable=z_ddr_line_cache complete dim=1
        color_ddr_word_t color_ddr_line_cache[TILE_WIDTH / COLOR_PER_WORD];
        #pragma HLS ARRAY_PARTITION variable=color_ddr_line_cache complete dim=1

        ap_uint<32> current_row_length_px = tile_global_max_x_px - tile_global_min_x_px + 1; 
        
        ap_uint<32> z_ddr_start_word_idx = (y * config.max_x_res + tile_global_min_x_px) / Z_PER_WORD;
        ap_uint<32> num_z_words_to_process = (current_row_length_px + Z_PER_WORD - 1) / Z_PER_WORD; 
        Z_READ_DDR_LINE_LOOP:
        for (ap_uint<8> i = 0; i < num_z_words_to_process; ++i) {
            #pragma HLS LOOP_TRIPCOUNT min=1 max=(TILE_WIDTH / Z_PER_WORD) // 修正
            z_ddr_line_cache[i] = output_zbuffer_ddr_write[z_ddr_start_word_idx + i]; 
        }

        ap_uint<32> color_ddr_start_word_idx = (y * config.max_x_res + tile_global_min_x_px) / COLOR_PER_WORD;
        ap_uint<32> num_color_words_to_process = (current_row_length_px + COLOR_PER_WORD - 1) / COLOR_PER_WORD; 
        COLOR_READ_DDR_LINE_LOOP:
        for (ap_uint<8> i = 0; i < num_color_words_to_process; ++i) {
            #pragma HLS LOOP_TRIPCOUNT min=1 max=(TILE_WIDTH / COLOR_PER_WORD)
            color_ddr_line_cache[i] = output_framebuffer_ddr[color_ddr_start_word_idx + i]; 
        }

        FLUSH_LINE_TO_DDR_PROCESS_PIXELS: 
        for (fpal::fp_screen_pixel_idx_t x = tile_global_min_x_px; x <= tile_global_max_x_px; ++x) {
            #pragma HLS LOOP_TRIPCOUNT min=1 max=TILE_WIDTH

            int local_line_x_idx = (int)(x - tile_global_min_x_px);
            
            fpal::fp_z_buffer_t final_z = line_z_buffer[local_line_x_idx];
            bool pixel_updated = (final_z != (fpal::fp_z_buffer_t)65535);

            // 更新局部计数器
            tile_actual_writes_to_ddr += pixel_updated ? 1 : 0;

            ap_uint<32> z_word_local_idx = local_line_x_idx / Z_PER_WORD;
            ap_uint<3> z_sub_word_offset = local_line_x_idx % Z_PER_WORD;
            zbuffer_ddr_word_t current_z_ddr_word = z_ddr_line_cache[z_word_local_idx];
            zbuffer_ddr_word_t z_mask = Z_MASK_16BIT << (z_sub_word_offset * 16);
            zbuffer_ddr_word_t new_z_slot_val = ((zbuffer_ddr_word_t)final_z) << (z_sub_word_offset * 16);
            
            // --- DEBUG: 仅对第一个 Tile 的前5个或后5个像素进行详细打印 ---
            #ifndef __SYNTHESIS__
            if (tile_y_idx == 0 && tile_x_idx == 0 && (x < tile_global_min_x_px + 5 || x > tile_global_max_x_px - 5)) {
                 if (pixel_updated) {
                    std::cout << "[HLS_RASTER_DEBUG] Tile(" << (int)tile_x_idx << "," << (int)tile_y_idx << ") Pixel(" << (int)x << "," << (int)y << ") UPDATED." << std::endl;
                    std::cout << "  Calculated Z: " << final_z << std::endl;
                    std::cout << "  Calculated Color (R,G,B): (" 
                              << (int)line_color_R[local_line_x_idx] << "," 
                              << (int)line_color_G[local_line_x_idx] << "," 
                              << (int)line_color_B[local_line_x_idx] << ")" << std::endl;
                 } else {
                    // std::cout << "[HLS_RASTER_DEBUG] Tile(" << (int)tile_x_idx << "," << (int)tile_y_idx << ") Pixel(" << (int)x << "," << (int)y << ") NOT UPDATED (Z_farthest)." << std::endl;
                 }
                 if (pixel_updated) { // 仅当像素被更新时才打印DDR写入信息
                     std::cout << "  Z-Buffer: current_z_ddr_word [hex]: " << std::hex << std::setw(16) << std::setfill('0') << current_z_ddr_word << std::dec << std::endl;
                     std::cout << "  Z-Buffer: z_mask [hex]:             " << std::hex << std::setw(16) << std::setfill('0') << z_mask << std::dec << std::endl;
                     std::cout << "  Z-Buffer: new_z_slot_val [hex]:     " << std::hex << std::setw(16) << std::setfill('0') << new_z_slot_val << std::dec << std::endl;
                     std::cout << "  Z-Buffer: Resulting word for cache [hex]: " << std::hex << std::setw(16) << std::setfill('0') << ((current_z_ddr_word & ~z_mask) | new_z_slot_val) << std::dec << std::endl;
                 }
            }
            #endif
            // --- END DEBUG ---

            z_ddr_line_cache[z_word_local_idx] = pixel_updated 
                                                  ? ((current_z_ddr_word & ~z_mask) | new_z_slot_val)
                                                  : current_z_ddr_word;

            ap_uint<32> color_word_local_idx = local_line_x_idx / COLOR_PER_WORD;
            ap_uint<1> color_sub_word_offset = local_line_x_idx % COLOR_PER_WORD;
            color_ddr_word_t current_color_ddr_word = color_ddr_line_cache[color_word_local_idx];

            // 关键修改：打包为 24 位 BGR 格式 (B, G, R 各占 8 位)
            // 根据 BMP 格式通常是 BGR 存储，这里我保持了原始代码的位移顺序，
            // 它是 R(16-23), G(8-15), B(0-7)，也就是 RGB 顺序。
            // 如果调试结果显示 `line_color_R=0, G=255, B=0` 并且 `new_packed_color` 是 `0x00FF00`
            // 这表示打包是 R-G-B 顺序的。
            // 那么，如果 BMP 文件期望的是 BGR，并且你输入 R=255, G=0, B=0 最终显示绿色，
            // 根本问题是 `line_color_R/G/B` 的值已经被交换，而不是这里的打包顺序。
            // 此处保持代码逻辑不变，因为日志显示它正在正确地根据 `line_color_R/G/B` 的输入打包。
            // 如果后续确认是这里需要调整为 BGR，则需要将 R 和 B 的位移交换。
            ap_uint<24> new_packed_color = 0;
            new_packed_color |= ((ap_uint<24>)line_color_R[local_line_x_idx] << 16); // R (bits 16-23)
            new_packed_color |= ((ap_uint<24>)line_color_G[local_line_x_idx] << 8);  // G (bits 8-15)
            new_packed_color |= ((ap_uint<24>)line_color_B[local_line_x_idx] << 0);  // B (bits 0-7)
            
            // 将 24 位 BGR 颜色放置到 32 位槽的低 24 位
            color_ddr_word_t color_mask_slot;
            color_ddr_word_t new_color_slot_val;

            if (color_sub_word_offset == 0) { // 64位字的低 32 位槽
                color_mask_slot = (PIXEL_SLOT_MASK << 0); // 清除整个 32 位槽
                new_color_slot_val = ((color_ddr_word_t)new_packed_color << 0); // 24 位颜色放置在槽的低 24 位
            } else { // 64位字的高 32 位槽
                color_mask_slot = (PIXEL_SLOT_MASK << 32); // 清除整个 32 位槽
                new_color_slot_val = ((color_ddr_word_t)new_packed_color << 32); // 24 位颜色放置在槽的低 24 位
            }
            
            // --- DEBUG: 仅对第一个 Tile 的前5个或后5个像素进行详细打印 ---
            #ifndef __SYNTHESIS__
            if (tile_y_idx == 0 && tile_x_idx == 0 && (x < tile_global_min_x_px + 5 || x > tile_global_max_x_px - 5) && pixel_updated) {
                 std::cout << "  Color: new_packed_color [hex]:   " << std::hex << std::setw(6) << std::setfill('0') << new_packed_color << std::dec << std::endl;
                 std::cout << "  Color: current_color_ddr_word [hex]: " << std::hex << std::setw(16) << std::setfill('0') << current_color_ddr_word << std::dec << std::endl;
                 std::cout << "  Color: color_mask_slot [hex]:      " << std::hex << std::setw(16) << std::setfill('0') << color_mask_slot << std::dec << std::endl;
                 std::cout << "  Color: new_color_slot_val [hex]:   " << std::hex << std::setw(16) << std::setfill('0') << new_color_slot_val << std::dec << std::endl;
                 std::cout << "  Color: Resulting word for cache [hex]: " << std::hex << std::setw(16) << std::setfill('0') << ((current_color_ddr_word & ~color_mask_slot) | new_color_slot_val) << std::dec << std::endl;
                 std::cout << "--------------------------------------------------------" << std::endl;
            }
            #endif
            // --- END DEBUG ---
            
            color_ddr_line_cache[color_word_local_idx] = pixel_updated
                                                         ? ((current_color_ddr_word & ~color_mask_slot) | new_color_slot_val)
                                                         : current_color_ddr_word;
        } 

        Z_WRITE_DDR_LINE_LOOP:
        for (ap_uint<8> i = 0; i < num_z_words_to_process; ++i) {
            #pragma HLS LOOP_TRIPCOUNT min=1 max=(TILE_WIDTH / Z_PER_WORD) // 修正
            output_zbuffer_ddr_write[z_ddr_start_word_idx + i] = z_ddr_line_cache[i]; 
        }

        COLOR_WRITE_DDR_LINE_LOOP:
        for (ap_uint<8> i = 0; i < num_color_words_to_process; ++i) {
            #pragma HLS LOOP_TRIPCOUNT min=1 max=(TILE_WIDTH / COLOR_PER_WORD) // 修正
            output_framebuffer_ddr[color_ddr_start_word_idx + i] = color_ddr_line_cache[i]; 
        }
    } // end RASTER_TILE_Y_LOOP

    // 将当前 Tile 的累加值写入 stream
    s_tile_pixel_write_counts.write(tile_actual_writes_to_ddr);
}

// 封装所有 Tile 循环的函数，以符合 DATAFLOW 规范
void process_all_tiles_dataflow(
    const RasterizerConfig& config,
    binned_triangle_packet_fixed all_triangles_bram[MAX_NUM_TRIANGLES],
    ap_uint<TILE_LIST_MAX_TRIANGLES_PER_TILE_LOG2> local_tile_list_count[MAX_NUM_TILES_Y][MAX_NUM_TILES_X],
    ap_uint<TRIANGLE_ID_BITS> local_tile_list_data[MAX_NUM_TILES_Y][MAX_NUM_TILES_X][TILE_LIST_MAX_TRIANGLES_PER_TILE],
    zbuffer_ddr_word_t* output_zbuffer_ddr_write,
    color_ddr_word_t* output_framebuffer_ddr,
    hls::stream<PixelWriteCount>& s_tile_pixel_write_counts // 输出到 stream
) {
    #pragma HLS INLINE OFF // 作为一个独立的 DATAFLOW 进程
    #pragma HLS DATAFLOW // 内部的 Tile 循环也可能受益于 DATAFLOW

    // 绑定 DDR 接口，如果这个函数直接操作 DDR
    // ZBUFFER_MAX_WORDS = 640 * 480 / 4 = 76800 words
    // FRAMEBUFFER_MAX_WORDS = 640 * 480 / 2 = 153600 words (每个 64 位字 2 个 32 位槽)
    #pragma HLS INTERFACE m_axi port=output_zbuffer_ddr_write offset=slave bundle=m_axi_gmem_zb_rw max_write_burst_length=256 max_read_burst_length=256 latency=60 num_read_outstanding=16 num_write_outstanding=16 depth=76800 // 修正 depth
    #pragma HLS INTERFACE m_axi port=output_framebuffer_ddr offset=slave bundle=m_axi_gmem_fb_write max_read_burst_length=256 max_write_burst_length=256 latency=60 num_read_outstanding=16 num_write_outstanding=16 depth=153600 // 修正 depth

    TILE_LOOP_Y: // 这里的 TILE_LOOP 将在 DATAFLOW 模式下被流水化
    for (ap_uint<8> tile_y_idx = 0; tile_y_idx < config.num_tiles_y; ++tile_y_idx) { // 使用 config.num_tiles_y
        #pragma HLS LOOP_TRIPCOUNT min=1 max=MAX_NUM_TILES_Y // TRIPCOUNT 修正
        TILE_LOOP_X:
        for (ap_uint<8> tile_x_idx = 0; tile_x_idx < config.num_tiles_x; ++tile_x_idx) { // 使用 config.num_tiles_x
            #pragma HLS LOOP_TRIPCOUNT min=1 max=MAX_NUM_TILES_X // TRIPCOUNT 修正
            #pragma HLS PIPELINE II=1 // 强制 Tile 之间的处理流水线化
            // 调用辅助函数处理单个 Tile
            rasterize_single_tile(
                tile_y_idx, tile_x_idx,
                config, // 传递 config 结构体
                all_triangles_bram,
                local_tile_list_count, local_tile_list_data,
                output_zbuffer_ddr_write, output_framebuffer_ddr,
                s_tile_pixel_write_counts
            );
        }
    }
}

// 汇总像素写入计数的函数，以符合 DATAFLOW 规范
void sum_pixel_write_counts_dataflow(
    const RasterizerConfig& config,
    hls::stream<PixelWriteCount>& s_tile_pixel_write_counts_in,
    ap_uint<32>& total_actual_writes_to_ddr_out
) {
    #pragma HLS INLINE OFF // 作为一个独立的 DATAFLOW 进程
    ap_uint<32> total_actual_writes_to_ddr = 0;
    SUM_PIXEL_WRITE_COUNTS:
    for (ap_uint<32> i = 0; i < config.num_tiles_x * config.num_tiles_y; ++i) { // 使用 config.num_tiles_x/y
        #pragma HLS LOOP_TRIPCOUNT min=1 max=(MAX_NUM_TILES_X*MAX_NUM_TILES_Y) // TRIPCOUNT 修正
        #pragma HLS PIPELINE II=1
        total_actual_writes_to_ddr += s_tile_pixel_write_counts_in.read();
    }
    total_actual_writes_to_ddr_out = total_actual_writes_to_ddr;
}


// ===========================================================
// TBR_Rasterizer 模块主实现 (DATAFLOW 优化)
// ===========================================================
void tbr_rasterizer_with_bram_read(
    binned_triangle_packet_fixed all_triangles_bram[MAX_NUM_TRIANGLES], // 共享 BRAM 数组
    hls::stream<TileListDataPacket>& s_tile_list_in, // 从流中读取 Tile List 数据
    hls::stream<ap_uint<16>>& s_num_triangles_to_rasterizer, // 接收到的三角形总数，通过 stream 传递 
    hls::stream<ap_uint<11>>& s_max_x_res_to_rasterizer,                // 最大X分辨率，通过 stream 传递
    hls::stream<ap_uint<11>>& s_max_y_res_to_rasterizer,                // 最大Y分辨率，通过 stream 传递
    zbuffer_ddr_word_t* output_zbuffer_ddr_write, // Z-buffer (R/W with cache)
    color_ddr_word_t* output_framebuffer_ddr,         // Framebuffer (R/W)
    ap_uint<32>& output_actual_write_ops               // 输出参数，报告实际写入DDR的像素数
) {
    #pragma HLS INLINE OFF // 这是一个 DATAFLOW 阶段，其自身不应被内联
    #pragma HLS DATAFLOW

    // TBR_Rasterizer 模块内部的接口声明
    // ZBUFFER_MAX_WORDS = 640 * 480 / 4 = 76800 words
    // FRAMEBUFFER_MAX_WORDS = 640 * 480 / 2 = 153600 words (每个 64 位字 2 个 32 位槽)
    #pragma HLS INTERFACE m_axi port=output_zbuffer_ddr_write offset=slave bundle=m_axi_gmem_zb_rw max_read_burst_length=256 max_write_burst_length=256 latency=60 num_read_outstanding=16 num_write_outstanding=16 depth=76800 // 修正 depth
    #pragma HLS INTERFACE m_axi port=output_framebuffer_ddr offset=slave bundle=m_axi_gmem_fb_write max_read_burst_length=256 max_write_burst_length=256 latency=60 num_read_outstanding=16 num_write_outstanding=16 depth=153600 // 修正 depth
    
    // 从流中读取的参数接口
    #pragma HLS INTERFACE axis port=s_tile_list_in
    #pragma HLS INTERFACE axis port=s_num_triangles_to_rasterizer // 此处用于接收转发的 num_triangles
    #pragma HLS INTERFACE axis port=s_max_x_res_to_rasterizer
    #pragma HLS INTERFACE axis port=s_max_y_res_to_rasterizer

    #pragma HLS INTERFACE s_axilite port=output_actual_write_ops bundle=ctrl_s_axilite_tbr
    #pragma HLS INTERFACE s_axilite port=return bundle=ctrl_s_axilite_tbr

    // 共享 BRAM 接口 (all_triangles_bram 依然是共享 BRAM)
    #pragma HLS bind_storage variable=all_triangles_bram type=ram_t2p impl=bram

    // Stage 0: Read configuration parameters (消除 DATAFLOW 警告)
    RasterizerConfig config;
    read_rasterizer_config(
        s_num_triangles_to_rasterizer,
        s_max_x_res_to_rasterizer,
        s_max_y_res_to_rasterizer,
        config
    );

    // 在 TBR_Rasterizer 内部声明 Tile List 的本地缓存
    // 这将作为从流中接收数据后的本地存储，供随机访问。
    static ap_uint<TILE_LIST_MAX_TRIANGLES_PER_TILE_LOG2> local_tile_list_count[MAX_NUM_TILES_Y][MAX_NUM_TILES_X];
    static ap_uint<TRIANGLE_ID_BITS> local_tile_list_data[MAX_NUM_TILES_Y][MAX_NUM_TILES_X][TILE_LIST_MAX_TRIANGLES_PER_TILE]; 
    #pragma HLS bind_storage variable=local_tile_list_count type=ram_t2p impl=bram
    #pragma HLS bind_storage variable=local_tile_list_data type=ram_t2p impl=bram
    
    // 用于传递每个 Tile 的像素写入计数的 stream
    hls::stream<PixelWriteCount> s_tile_pixel_write_counts;
    #pragma HLS STREAM variable=s_tile_pixel_write_counts depth=256 // 增加深度，以应对可能的数据突发

    // Stage 1.5: Consume all Tile List data from stream and populate local BRAMs (调用独立函数)
    write_tile_list_to_bram(s_tile_list_in, config.num_tiles_x, config.num_tiles_y, local_tile_list_count, local_tile_list_data);

    // Stage 2: Iterate through all tiles (使用 local_tile_list_count 和 local_tile_list_data)
    // 调用辅助函数 process_all_tiles_dataflow
    process_all_tiles_dataflow(
        config, // 传递 config 结构体
        all_triangles_bram,
        local_tile_list_count, local_tile_list_data,
        output_zbuffer_ddr_write, output_framebuffer_ddr,
        s_tile_pixel_write_counts
    );

    // Stage 3: 汇总所有 Tile 的像素写入计数
    // 调用辅助函数 sum_pixel_write_counts_dataflow
    sum_pixel_write_counts_dataflow(
        config,
        s_tile_pixel_write_counts,
        output_actual_write_ops
    );
}
